﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SerialPortHelperLib
{
  public  class FlashOperate
    {

        public enum BaseRegisterMap : uint
        {
            IR_BASE_ADDR = 0xC2000400,
            SPI_BASE_ADDR = 0x82000000,
            SDRAM_BASE_ADDR = 0xC4000000,
        }

        public enum SPIRegisterMap : uint
        {

            SPI_FUNCTION_SELECT = 0x00000000,
            SPI_CONTROL = 0x00000004,
            SPI_RESERVED = 0x00000008,
            SPI_SHIFT_CONTROL = 0x0000000c,
            SPI_SHIFT_TXD0 = 0x00000010,
            SPI_SHIFT_TXD1 = 0x00000014,
            SPI_SHIFT_TXD2 = 0x00000018,
            SPI_SHIFT_TXD3 = 0x0000001C,
            SPI_SHIFT_RXD0 = 0x00000020,
            SPI_SHIFT_RXD1 = 0x00000024,
            SPI_SHIFT_RXD2 = 0x00000028,
            SPI_SHIFT_RXD3 = 0x0000002C,
            SPI_INT_STATUS = 0x00000030,
            SPI_INT_MASK = 0x00000034,
            SPI_BUSY = 0x00000038
        }


        private SerialPort sPortTemp;

        //public delegate void SendEventFlashOperateNewClick(string msg);

        //public event SendEventFlashOperateNewClick SendFlashOperateClick;

        private Sensor_i2c sensor;


        public FlashOperate(SerialPort _sPortTemp) {
            sPortTemp = _sPortTemp;
            sensor = new Sensor_i2c(0, 0, 0, false, false, false, sPortTemp);
        }

        public void SPIenable() {
           
            long test_value1 = (long)BaseRegisterMap.SPI_BASE_ADDR;
            uint test_value2 = (uint)SPIRegisterMap.SPI_FUNCTION_SELECT;
            uint FUNCT_SEL_ADDR = (uint)(test_value1 + test_value2);
            sensor.SendRegDataARM(0x1, FUNCT_SEL_ADDR, 0);
            uint recdata = 0;
            sensor.ReadRegDataARM(0x31, 0x80500200, ref recdata);
            recdata = (uint)recdata & (~0x000000f0U);
            sensor.SendRegDataARM(0x21, 0x80500200, recdata);
        }

        public string  FlashRead(uint flash_address) {

            long test_value1 = (long)BaseRegisterMap.SPI_BASE_ADDR;

            uint test_value2 = (uint)SPIRegisterMap.SPI_FUNCTION_SELECT;
            uint FUNCT_SEL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_CONTROL;
            uint CONTROL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_CONTROL;
            uint SHIFT_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD0;
            uint TXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD1;
            uint TXD1_ADDR = (uint)(test_value1 + test_value2);


            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD0;
            uint RXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD1;
            uint RXD1_ADDR = (uint)(test_value1 + test_value2);

            uint spi_shift_cnt;
            uint spi_rxvld_cnt;
            uint senddata;
            uint recvdata = 0;
            uint op_code = 0x03;

            sensor.SendRegDataARM(0x1, FUNCT_SEL_ADDR, 0x1);
            Thread.Sleep(200);

            //TXD0
            senddata = (((flash_address & 0xff) << 24) + ((flash_address & 0xff00) << 8) + ((flash_address & 0xff0000) >> 8) + op_code);
            //DWordInverse(ref senddata);
            sensor.SendRegDataARM(0x1, TXD0_ADDR, senddata);
            //Thread.Sleep(200);

            //SHIFT_CONTROL
            spi_shift_cnt = 64;
            spi_rxvld_cnt = 32;
            senddata = (3 << 16) + (spi_rxvld_cnt << 8) + (spi_shift_cnt << 0);
            sensor.SendRegDataARM(0x1, SHIFT_ADDR, senddata);
            Thread.Sleep(200);

            //this.textBox_disp.AppendText("Read RXD0 Data: ");
            sensor.ReadRegDataARM(0x11, RXD0_ADDR, ref recvdata);

            return Convert.ToString(recvdata, 16).ToUpper();
        }

        public void FlashWrite(uint flash_address, uint flash_data) {
            long test_value1 = (long)BaseRegisterMap.SPI_BASE_ADDR;

            uint test_value2 = (uint)SPIRegisterMap.SPI_FUNCTION_SELECT;
            uint FUNCT_SEL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_CONTROL;
            uint CONTROL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_CONTROL;
            uint SHIFT_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD0;
            uint TXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD1;
            uint TXD1_ADDR = (uint)(test_value1 + test_value2);


            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD0;
            uint RXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD1;
            uint RXD1_ADDR = (uint)(test_value1 + test_value2);

            uint spi_shift_cnt;
            uint spi_rxvld_cnt;
            uint senddata;
            uint recvdata = 0;

            //spi mode
            sensor.SendRegDataARM(0x1, FUNCT_SEL_ADDR, 0x1);

            //spi cs 片选
            uint spi_cs = 1;
            sensor.ReadRegDataARM(0x11, CONTROL_ADDR, ref recvdata);
            senddata = recvdata & 0xffff3cff;
            senddata = senddata + (spi_cs << 8);
            //senddata = senddata + (spi_cs << 8); senddata = (0xb << 24) + (spi_cs << 8) + 0x08;
            sensor.SendRegDataARM(0x1, CONTROL_ADDR, senddata);

            FlashReadStatus(ref recvdata);

            FlashWriteEnable();
            FlashReadStatus(ref recvdata);

            //unprotected
            senddata = (((flash_address & 0xff) << 24) + ((flash_address & 0xff00) << 8) + ((flash_address & 0xff0000) >> 8) + 0x39);
            sensor.SendRegDataARM(0x1, TXD0_ADDR, senddata);
            //SHIFT_CONTROL
            spi_shift_cnt = 32;
            spi_rxvld_cnt = 0;
            senddata = (3 << 16) + (spi_rxvld_cnt << 8) + (spi_shift_cnt << 0);
            sensor.SendRegDataARM(0x1, SHIFT_ADDR, senddata);
            Thread.Sleep(200);

            FlashReadStatus(ref recvdata);

            FlashWriteEnable();
            FlashReadStatus(ref recvdata);

            //write data
            //TXD0
            senddata = (((flash_address & 0xff) << 24) + ((flash_address & 0xff00) << 8) + ((flash_address & 0xff0000) >> 8) + 0x02);
            sensor.SendRegDataARM(0x1, TXD0_ADDR, senddata);
            //TXD1
            //senddata = (((flash_data & 0xff) << 24) + ((flash_data & 0xff00) << 8) + ((flash_data & 0xff0000) >> 8) + (flash_data >> 24));
            //senddata = (((flash_data & 0xff) << 24) | ((flash_data & 0xff00) << 8) | (((flash_data >> 16) & 0xff) << 8) | ((flash_data >> 24) & 0xff));
            senddata = flash_data;
            sensor.SendRegDataARM(0x1, TXD1_ADDR, senddata);
            //SHIFT_CONTROL
            spi_shift_cnt = 64;
            spi_rxvld_cnt = 0;
            senddata = (3 << 16) + (spi_rxvld_cnt << 8) + (spi_shift_cnt << 0);
            sensor.SendRegDataARM(0x1, SHIFT_ADDR, senddata);
            Thread.Sleep(200);
        }

        private void FlashWriteEnable()
        {
            long test_value1 = (long)BaseRegisterMap.SPI_BASE_ADDR;

            uint test_value2 = (uint)SPIRegisterMap.SPI_FUNCTION_SELECT;
            uint FUNCT_SEL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_CONTROL;
            uint CONTROL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_CONTROL;
            uint SHIFT_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD0;
            uint TXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD1;
            uint TXD1_ADDR = (uint)(test_value1 + test_value2);


            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD0;
            uint RXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD1;
            uint RXD1_ADDR = (uint)(test_value1 + test_value2);

            uint spi_shift_cnt;
            uint spi_rxvld_cnt;
            uint senddata;
            uint op_code = 0x06;

            //打开写使能
            senddata = op_code;
            //DWordInverse(ref senddata);
            sensor.SendRegDataARM(0x1, TXD0_ADDR, senddata);
            //SHIFT_CONTROL
            spi_shift_cnt = 8;
            spi_rxvld_cnt = 0;
            senddata = (3 << 16) + (spi_rxvld_cnt << 8) + (spi_shift_cnt << 0);
            sensor.SendRegDataARM(0x1, SHIFT_ADDR, senddata);
            Thread.Sleep(2);
        }

        private void FlashReadStatus(ref uint recvdata)
        {
            long test_value1 = (long)BaseRegisterMap.SPI_BASE_ADDR;

            uint test_value2 = (uint)SPIRegisterMap.SPI_FUNCTION_SELECT;
            uint FUNCT_SEL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_CONTROL;
            uint CONTROL_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_CONTROL;
            uint SHIFT_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD0;
            uint TXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_TXD1;
            uint TXD1_ADDR = (uint)(test_value1 + test_value2);


            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD0;
            uint RXD0_ADDR = (uint)(test_value1 + test_value2);

            test_value2 = (uint)SPIRegisterMap.SPI_SHIFT_RXD1;
            uint RXD1_ADDR = (uint)(test_value1 + test_value2);

            uint spi_shift_cnt;
            uint spi_rxvld_cnt;
            uint senddata;
            //uint recvdata = 0;
            uint op_code = 0x05;

            //read stauts
            senddata = op_code;
            sensor.SendRegDataARM(0x1, TXD0_ADDR, senddata);

            //SHIFT_CONTROL
            spi_shift_cnt = 16;
            spi_rxvld_cnt = 8;
            senddata = (3 << 16) + (spi_rxvld_cnt << 8) + (spi_shift_cnt << 0);
            sensor.SendRegDataARM(0x1, SHIFT_ADDR, senddata);
            Thread.Sleep(2);

            //this.textBox_disp.AppendText("Read RXD0 Data: \n");
            sensor.ReadRegDataARM(0x11, RXD0_ADDR, ref recvdata);

            //value = recvdata;
        }
    }
}
